import os
import queue
import threading
import time
import re

from netmiko import ConnectHandler
from openpyxl import load_workbook

from AES import prpcrypt
from office_to_pdf import PDFConverter
from send_email import Email

# 设备配置文件路径
DEVICES_INFO_PATH = 'DEVICES.cfg'
LOG_PATH = 'LOG'
THREADING_NUM = 10
# The number of threading
CMD_DELAY = 1
# sleep time
Q = queue.Queue(THREADING_NUM)
# FIFO
queueLock = threading.Lock()


# for print
def show_info(msg):
    queueLock.acquire()
    print(msg)
    queueLock.release()


####################################################################
def get_devices_info():
    # FORMAT:devicename ip username password cmd
    try:
        with open(DEVICES_INFO_PATH, 'r') as f:
            for line in f:
                if len(line) == 1:
                    # ignore blank line (len('\n')==1)
                    continue
                info_line = line.split()
                # using whitespace as the delimiter string(leading and trailing whitespace removed)
                if info_line[0][0] == '#':
                    # ignore comment line
                    continue
                else:
                    info_dict = {
                        'devicename': info_line[0],
                        'ip': info_line[1],
                        'username': pc.decrypt(info_line[2]),
                        'password': pc.decrypt(info_line[3]),
                        'cmd': info_line[4]
                    }
                    yield info_dict
    except FileNotFoundError as e:
        show_info('Can not find "{}"'.format(DEVICES_INFO_PATH))
    except IndexError as e:
        show_info('"{}" format error'.format(DEVICES_INFO_PATH))

    ####################################################################


def get_cmd_info(CMD_Info_Path):
    CMD = []
    DEVICES_TYPE = ''
    try:
        with open(CMD_Info_Path, 'r') as f:
            for line in f:
                if len(line) == 1:
                    continue
                # ignore blank line (len('\n')==1)
                cmd_line = line.strip()
                # leading and trailing whitespace removed
                if cmd_line[0] == '#':
                    continue
                # ignore comment line
                if cmd_line[:12] == 'device_type:':
                    DEVICES_TYPE = cmd_line[12:]
                    # get device_type
                else:
                    CMD.append(cmd_line)
            if DEVICES_TYPE == '':
                raise UnboundLocalError('No Device Type')
            return DEVICES_TYPE, CMD
    except FileNotFoundError as e:
        show_info('Can not find "{}"'.format(CMD_Info_Path))
    except UnboundLocalError as e:
        show_info('Can not find "device_type" in "{}"'.format(CMD_Info_Path))

    ####################################################################


def run_cmd(host, commands, device_type):
    Q.put(host)
    print('Start......{}-{}'.format(host['ip'], host['devicename']))
    try:
        host_netmiko = {
            'device_type': device_type,
            'ip': host['ip'],
            'username': host['username'],
            'password': host['password'],
            'port': 22
        }
        # Use netmiko:
        net_connect = ConnectHandler(**host_netmiko)
        dirname = host['ip'] + '_' + host['devicename']
        dirpath = 'E:/工作/01日常及运维工作/巡检报告/' + LogTime + '/' + dirname
        # os.makedirs('LOG'+ '\\' + LogTime + '\\' + dirname) #The same effect
        os.makedirs(dirpath)
        # Create a log directory
        out_dict = dict()
        for cmd in commands:
            output = net_connect.send_command(cmd)
            time.sleep(CMD_DELAY)
            format_cmd = cmd.replace(':', '_').replace('|', '_')
            # replace special characters
            # Write the log
            with open(dirpath + '/' + format_cmd + '.txt', "w") as f:
                f.write(cmd)
                f.write('\n')
                f.write(output)
                out_dict['devicename'] = host['devicename']
                if 'cpu' in format_cmd:
                    matchObj = re.findall(r'([0-9].?%) in last 5 seconds', output)
                    out_dict['cpu'] = matchObj[0]
                elif 'memory' in format_cmd:
                    matchObj = re.findall(r'[0-9].?.{0,1}[0-9].?%', output)
                    out_dict['memory'] = matchObj[0]
                elif 'fan' in format_cmd:
                    matchObj = re.findall(r': (\S+)', output)
                    out_dict['fan1'] = matchObj[0]
                    if host['devicename'] != 'w_core_sw':
                        out_dict['fan2'] = matchObj[1]
                elif 'environment' in format_cmd:
                    matchObj = re.findall(r'hotspot [0-9] ([0-9]*)', output)
                    matchObj.sort(reverse=True)
                    out_dict['Temperature'] = matchObj[0]
                elif 'version' in format_cmd:
                    matchObj = re.findall(r'uptime is (.*)?', output)
                    out_dict['uptime'] = matchObj[0]
                elif 'interface' in format_cmd:
                    if host['devicename'] != 'w_core_sw':
                        matchObj = re.findall(r'(\S+)', output)
                        out_dict['interface'] = matchObj[1]
                    else:
                        matchObj = re.findall(r'GE2/0/48             (\S+)', output)
                        out_dict['interface'] = matchObj[0]
                elif 'dot1x' in format_cmd and host['devicename'] != 'w_core_sw':
                    matchObj = re.findall(r'GigabitEthernet1/0/([0-9]*)', output)
                    res = [str(x) for x in range(int(matchObj[0]), int(matchObj[-1]) + 1) if str(x) not in matchObj]
                    if len(res) > 0:
                        out_dict['dot1x'] = ','.join(res) + '号端口未开启dot1x'
                    else:
                        out_dict['dot1x'] = '均已开启dot1x'
                out_list.append(out_dict)
        show_info('Finished...{}-{}'.format(host['ip'], host['devicename']))
        net_connect.disconnect()
    except:
        show_info('Failed.....{}-{} <Please check the fail.txt>'.format(host['ip'], host['devicename']))
        with open('fail.txt', "a+") as f:
            f.write(host['ip'] + '-' + host['devicename'] + '\n')
    finally:
        Q.get()
        Q.task_done()


####################################################################
# 提取信息至excel中
def put_to_excel(out_list):
    template_sheet.cell(row=3, column=2, value=LogTime)
    for row in (7, 16, 24, 32, 40):
        for sw in out_list:
            if sw['devicename'] == 'w_core_sw':
                template_sheet.cell(row=row, column=4, value=sw['uptime'])
                template_sheet.cell(row=row + 1, column=4, value=sw['Temperature'])
                template_sheet.cell(row=row + 2, column=4, value=sw['fan1'])
                template_sheet.cell(row=row + 3, column=4, value=sw['cpu'])
                template_sheet.cell(row=row + 4, column=4, value=sw['memory'])
                template_sheet.cell(row=row + 5, column=4, value=sw['interface'])
                continue
            elif sw['devicename'] == template_sheet.cell(row=row, column=1).value:
                template_sheet.cell(row=row, column=4, value=sw['uptime'])
                template_sheet.cell(row=row + 1, column=4, value=sw['Temperature'])
                template_sheet.cell(row=row + 2, column=4, value=sw['fan1'])
                template_sheet.cell(row=row + 3, column=4, value=sw['fan2'])
                template_sheet.cell(row=row + 4, column=4, value=sw['cpu'])
                template_sheet.cell(row=row + 5, column=4, value=sw['memory'])
                template_sheet.cell(row=row + 6, column=4, value=sw['interface'])
                template_sheet.cell(row=row + 7, column=4, value=sw['dot1x'])
    template_wb.save(target_name)


if __name__ == '__main__':
    LogTime = time.strftime('%Y-%m-%d_%H-%M-%S')
    # LogTime = '2022-06-24_14-14-14'
    pc = prpcrypt('***************')  # 初始化密钥
    # 以此将数据写如模板中，并另存为
    template_wb = load_workbook('巡检模板.xlsx')
    template_sheet = template_wb['Sheet1']
    base_dir = 'E:/工作/01日常及运维工作/巡检报告/'
    target_name = base_dir + LogTime + '/巡检报告.xlsx'
    # 定义存放结果的dict和list
    out_list = []

    threads = []
    if not os.path.exists('LOG'):
        os.makedirs('LOG')
    # Create a log directory
    if os.path.exists('fail.txt'):
        os.remove('fail.txt')
    # remove 'fail.txt'

    hosts = get_devices_info()
    # get hosts
    try:
        for i in hosts:
            device_type, commands = get_cmd_info(i['cmd'])
            # get device_type and cmds
            task = threading.Thread(target=run_cmd, args=(i, commands, device_type))
            threads.append(task)
        for t in threads:
            t.start()
        for t in threads:
            t.join()
        show_info('All done.')
        put_to_excel(out_list)
        pathname = base_dir + LogTime + '/巡检报告.xlsx'
        pdfConverter = PDFConverter(pathname, LogTime, base_dir)
        pdfConverter.run_conver()
        # 定义邮件内容
        body = '网络设备自动巡检报告，脚本发送请勿回复。'
        # "接收方的邮箱", "邮件标题", "邮件内容", "报告路径"
        Email("网络设备巡检", body=body, attachmentspath=base_dir + LogTime)
        print('邮件发送成功~！')
    except TypeError as e:
        show_info('Please check the error.')
